package com.hywood.manager.live.service;


import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.live.model.v20161101.ForbidLiveStreamRequest;
import com.aliyuncs.live.model.v20161101.ForbidLiveStreamResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hywood.errorenum.ResultEnum;
import com.hywood.exception.GlobalDefaultExceptionHandler;
import com.hywood.manager.live.dao.LiveDao;
import com.hywood.manager.live.entity.ChannelDto;
import com.hywood.manager.live.entity.PageResult;
import com.hywood.manager.live.liveinterface.ChannelInterface;
import com.hywood.manager.live.model.Channel;
import com.hywood.util.Result;
import com.hywood.util.ResultUtil;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * Created By HuJian on 2018/7/18
 */
@CrossOrigin("*")
@RestController
public class ChannelService implements ChannelInterface {
    private static final int EDIT_ABLE_STATUS = 4;
    private static final int LIVE_STATUS_STOP = 4;
    private static final int LIVE_STATUS_CLOSE = 5;
    private static final int LIVE_STATUS_NOT_PUSH = 9;
    private static final int LIVE_STATUS_NOT_START = 0;
    public static final String APP_NAME = "app";
    public static final String LIVE_ACTION = "publisher";
    public static final int DEFAULT_TIME_OUT = 5000;
    @Autowired
    private LiveDao liveDao;
    @Autowired
    private GlobalDefaultExceptionHandler globalDefultExceptionHandler;
    @Value("${aliyun.live.access-key-id}")
    private String accessKeyId;
    @Value("${aliyun.live.access-key-secret}")
    private String accessKeySecret;
    @Value("${aliyun.live.url}")
    private String liveUrl;
    private Logger log = LoggerFactory.getLogger("hywood-business");
    private Random random = new Random();
    private IAcsClient client;
    @Value("${aliyun.live.region-id}")
    private String regionId;

    /**
     * @param index 页码
     * @param size  分页大小
     * @return 分页后数据
     */
    @Override
    public Result listChannel(@PathVariable("index") Integer index, @RequestParam("size") Integer size) {
        PageHelper.startPage(index, size, " id desc ");
        List<Channel> result = liveDao.listChannel();
        if (result != null && !result.isEmpty()) {
            LocalDateTime now = LocalDateTime.now();
            result.forEach(channel -> {
                this.updateLiveStatus(now, channel);
            });
            return ResultUtil.success(new PageResult<List>(((Page) result).getTotal(), result));
        }
        return ResultUtil.error(ResultEnum.ERROR);
    }


    /**
     * 通过guid获取房间详细信息
     *
     * @param guid 房间guid
     * @return 房间信息
     */
    @Override
    public Result getChannelByGuid(@PathVariable("guid") String guid) {
        Channel result = liveDao.getChannelByGuid(guid);
        if (result != null) {
            LocalDateTime now = LocalDateTime.now();
            this.updateLiveStatus(now, result);
            return ResultUtil.success(result);
        }
        return ResultUtil.error(ResultEnum.ERROR);
    }

    /**
     * 创建房间
     *
     * @param channelDto Dto
     * @return 操作结果
     */
    @Override
    public Result insertChannel(@RequestBody ChannelDto channelDto) {
        Channel channel = new Channel();
        BeanUtils.copyProperties(channelDto, channel);
        channel.setLiveGuid(UUID.randomUUID().toString().replace("-", ""));
        String channelId = String.format("%06d", random.nextInt(1000000));
        for (; liveDao.getChannelByChannelId(channelId) != null; ) {
            channelId = String.format("%06d", random.nextInt(1000000));
        }
        channel.setChannelId(channelId);
        channel.setChannelPassword(String.format("%04d", random.nextInt(10000)));
        channel.setCreateUser("");
        channel.setUpdateUser("");
        liveDao.insert(channel);
        return ResultUtil.success();
    }

    /**
     * 删除频道
     *
     * @param guid 频道guid
     * @return 操作结果
     */
    @Override
    public Result deleteChannel(@PathVariable("guid") String guid) {
        liveDao.deleteByGuid(guid);
        return ResultUtil.success();
    }

    /**
     * 修改频道
     *
     * @param guid       频道guid
     * @param channelDto Dto
     * @return 操作结果
     */
    @Override
    public Result updateChannel(@PathVariable("guid") String guid, @RequestBody ChannelDto channelDto) {
        Channel channel = new Channel();
        Timestamp now = Timestamp.valueOf(LocalDateTime.now());
        BeanUtils.copyProperties(channelDto, channel);
        channel.setLiveGuid(guid);
        Channel oldInfo = liveDao.getChannelByGuid(guid);
        if (channel.getLiveStatus() == LIVE_STATUS_NOT_START && oldInfo.getLiveStartdate().before(now)) {
            return ResultUtil.error(-3, "保存失败，请重新刷新页面");
        }
        if (oldInfo.getLiveStatus() == LIVE_STATUS_NOT_START && oldInfo.getLiveStartdate().after(now)) {
            liveDao.updateAllByGuid(channel);
        } else if (oldInfo.getLiveStatus() < EDIT_ABLE_STATUS) {
            liveDao.updateModel(channel);
        } else {
            return ResultUtil.error(ResultEnum.ERROR);
        }

        return ResultUtil.success();
    }

    /**
     * 关闭频道
     *
     * @param guid 频道guid
     * @return 操作结果
     */
    @Override
    public Result closeChannel(@PathVariable("guid") String guid) {
        if (this.stopStreamPush(guid)) {
            liveDao.closeByGuid(guid);
            return ResultUtil.success();
        }
        return ResultUtil.error(-3,"关闭失败");
    }

    /**
     * @param index 页码
     * @param size  分页大小
     * @return 分页后数据
     */
    @Override
    public Result queryChannel(@PathVariable("index") Integer index, @RequestParam("size") Integer size, @RequestBody(required = false)ChannelDto channelDto) {
        Channel channel = new Channel();
        List<Channel> result;
        if (channelDto != null) {
            BeanUtils.copyProperties(channelDto, channel);
            if (channel.getActivityName() != null) {
                channel.setActivityName("%" + channel.getActivityName() + "%");
            }
            if (channel.getChannelName() != null) {
                channel.setChannelName("%" + channel.getChannelName() + "%");
            }
            PageHelper.startPage(index, size, " id desc ");
            result = liveDao.queryChannel(channel);
        } else {
            PageHelper.startPage(index, size, " id desc ");
            result = liveDao.listChannel();
        }
        if (result != null && !result.isEmpty()) {
            result.forEach(channel1 -> {
                this.updateLiveStatus(LocalDateTime.now(), channel1);
            });
            return ResultUtil.success(new PageResult<List>(((Page) result).getTotal(), result));
        }
        return ResultUtil.success();
    }

    /**
     * 直播上下线控制
     *
     * @param guid         直播guid
     * @param onlineStatus 上下线状态 0未上线 1 上线
     * @return 操作结果
     */
    @Override
    public Result setChannelOnlineStatus(@PathVariable String guid, @RequestParam Integer onlineStatus) {
        if (guid != null && onlineStatus != null) {
            liveDao.setChannelOnlineStatus(guid, onlineStatus);
            return ResultUtil.success();
        }
        return ResultUtil.error(ResultEnum.ERROR);
    }

    private void updateLiveStatus(LocalDateTime now, Channel channel) {
        if (channel.getLiveStatus() == LIVE_STATUS_CLOSE) {
            return;
        }
        if (channel.getLiveEnddate().before(Timestamp.valueOf(now))) {
            channel.setLiveStatus(LIVE_STATUS_STOP);
            return;
        }
        if (channel.getLiveStatus() != 0) {
            return;
        }
        if (channel.getLiveStartdate().before(Timestamp.valueOf(now))) {
            channel.setLiveStatus(LIVE_STATUS_NOT_PUSH);
        }

    }

    /**
     * 向阿里云请求关闭推流
     *
     * @param guid 房间guid
     * @return 成功/失败
     */
    private boolean stopStreamPush(String guid) {
        if (client == null) {
            DefaultProfile profile = DefaultProfile.getProfile(
                    regionId,
                    accessKeyId,
                    accessKeySecret);
            client = new DefaultAcsClient(profile);
        }
        ForbidLiveStreamRequest request = new ForbidLiveStreamRequest();
        request.setAppName(APP_NAME);
        request.setDomainName(liveUrl);
        request.setLiveStreamType(LIVE_ACTION);
        request.setStreamName(guid);
        request.setResumeTime(LocalDateTime.now().plusDays(1).toString().substring(0,19)+"Z");
        request.setSysReadTimeout(DEFAULT_TIME_OUT);
        request.setSysConnectTimeout(DEFAULT_TIME_OUT);
        ForbidLiveStreamResponse response;
        try {
            response = client.getAcsResponse(request);
            log.info("Close success,request :" + response.getRequestId());
            return true;
        } catch (ServerException e) {
            log.error("Aliyun server error:" + JSON.toJSONString(e));
        } catch (ClientException e) {
            log.error("Aliyun client error:" + JSON.toJSONString(e));
        }
        return false;
    }
}
